#include <string.h>

#include "data.h"




//Private Defines
#define DATA_LOCK_ENABLE		0

//Private Macros
#if DATA_LOCK_ENABLE
#define data_Lock()				os_sem_wait(&data_sem)
#define data_Unlock()			os_sem_signal(&data_sem)
#else
#define data_Lock()
#define data_Unlock()
#endif

//Private Variables
#if DATA_LOCK_ENABLE
static os_sem_t data_sem;
#endif


//Private Consts
flash_dev_t sfs_Para = {
	FLASH_DEV_INT,  64,	INTFLASH_BASE_ADR + 0xC0000,
};





//Private Functions
static void iap_Start(size_t iaplen)
{
	adr_t iapa = IAP_ADR_BEGIN;

	intf_Erase(IAP_ADR_FLAG);
	intf_Program(IAP_ADR_FLAG, (const void *)&iaplen, 4);
	intf_Program(IAP_ADR_FLAG + 4, (const void *)&iapa, 4);
}





void data_Init()
{
	u32 i = 0;

#if DATA_LOCK_ENABLE
	os_sem_init(&data_sem, 1);
#endif

	data_Lock();

	if (sfs_Read(&sfs_Para, PARA_ID_VERSOFT, &i, 4) < 0)
		sfs_Init(&sfs_Para);
	if (i != VER_SOFT)
	{
		i = VER_SOFT;
		sfs_Write(&sfs_Para, PARA_ID_VERSOFT, &i, 4);
	}

	data_Unlock();
}

void iap_Init()
{
	adr_t adr;

	data_Lock();

	for (adr = IAP_ADR_BEGIN; adr < IAP_ADR_END; adr += INTFLASH_BLK_SIZE)
	{
		intf_Erase(adr);
	}

	data_Unlock();
}

size_t iap_UpData(size_t offset, const void *data, size_t len)
{
	adr_t adr = IAP_ADR_BEGIN + offset;

	if (adr < IAP_ADR_END)
	{
		data_Lock();
		intf_Program(adr, data, len);	// ??????Flash
		data_Unlock();

		offset += len;
	}

	return offset;
}

size_t iap_UpEnd(size_t alen)
{
	u16 crc;

//	crc = crc16(0xFFFF, (const void *)IAP_ADR_BEGIN, 2032);
//	if (memcmp((const void *)(IAP_ADR_BEGIN + 2032), &crc, 2))
//		return 0;

//	crc = crc16(0xFFFF, (const void *)(IAP_ADR_BEGIN + 2048), alen - 2048);
//	if (memcmp((const void *)(IAP_ADR_BEGIN + 2034), &crc, 2))
//		return 0;

//	if (*(const u8 *)(IAP_ADR_BEGIN + 2036) != (VER_HARD + 0x33))
//		return 0;

	data_Lock();
	iap_Start(alen);
	data_Unlock();
	return alen;
}

u32 para_Get(sfs_id_t id)
{
 	u32 read = 0;

	para_Read(id, &read, 4);

	return read;
}

u32 para_GetDef(sfs_id_t id, u32 def)
{
	u32 tmp;
	int read;

	read = para_Read(id, &tmp, 4);

	return read > 0 ? tmp : def;
}

void para_Set(sfs_id_t id, u32 data)
{

	para_Write(id, &data, 4);
}

int para_Read(sfs_id_t id, void *data, size_t len)
{
 	int read;

	data_Lock();

	read = sfs_Read(&sfs_Para, id, data, len);
 
	data_Unlock();

	return read;
}

void para_Write(sfs_id_t id, const void *data, size_t len)
{

	data_Lock();

	sfs_Write(&sfs_Para, id, data, len);
 
	data_Unlock();
}


